﻿using Mapster;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;
using Shipeng.Util;
using SqlSugar;
using System.ComponentModel.DataAnnotations;
using System.Linq.Expressions;
using Yitter.IdGenerator;
using YNTK.Common.Const;
using YNTK.Common.Enum;
using YNTK.Common.Filter;
using YNTK.Data.MongoDB.Repositorie;
using YNTK.Dependency;
using YNTK.DynamicApiController;
using YNTK.FriendlyException;
using YNTK.LinqBuilder;
using YNTK.Mapster;
using YNTK.System.Entitys.Dto.Common;
using YNTK.System.Entitys.Permission;
using YNTK.System.Interfaces.Common;
using YNTK.System.Interfaces.Permission;
using YNTK.System.Interfaces.Resources;
using YNTK.VisitorsRecord.Entitys;
using YNTK.VisitorsRecord.Interface;

namespace YNTK.VisitorsRecord
{
    /// <summary>
    /// 访客记录服务的实现
    /// 版 本：V1.0.0.0
    /// 版 权：云南通科科技有限公司（https://www.yntkkj.com）
    /// 作 者：李仕鹏
    /// 日 期：2022.10.24 
    /// </summary>
    [ApiDescriptionSettings(Tag = "访客记录", Name = "Visitors", Order = 789)]
    [Route("api/[controller]")]
    public class VisitorsRecordService: IVisitorsRecordService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<VisitorsRecordEntity> _recordRepository;//访问记录仓储
        private readonly IMongoDBRepository<VisitorsRecordEntity> _recordMongoDbRepository;//访问记录mongodb仓储
        private readonly ISqlSugarRepository<VisitorsFilesEntity> _filesRepository;//访客记录相关附件仓储
        private readonly IMongoDBRepository<VisitorsFilesEntity> _filesMongoDbRepository;//访客记录相关附件mongodb仓储
        private readonly ISqlSugarRepository<ForeignDataEntity> _foreignRepository;//外来资料仓储
        private readonly IMongoDBRepository<ForeignDataEntity> _foreignMongoDbRepository;//外来资料mongodb仓储
        private readonly ISqlSugarRepository<ForeignDataFilesEntity> _foreignFileRepository;//外来资料相关附件仓储
        private readonly IMongoDBRepository<ForeignDataFilesEntity> _foreignFileMongoDbRepository;//外来资料相关附件mongodb仓储

        private readonly IMechanismService _mechanismService;//机构服务
        private readonly ITkUsersService _tkUsersService;//用户服务
        private readonly IDictionaryService _dictionaryService;//字典服务
        private readonly IFileService _fileService;//文件服务
        private readonly ITkRoleService _tkRoleService;//角色服务
        private readonly HttpContext _httpContext;

        private readonly string _records = "visitors_records";//mongodb中访客记录数据集名称
        private readonly string _files = "visitors_files";//mongodb中访客记录相关附件数据集名称
        private readonly string _foreigndata = "visitors_foreigndata";//mongodb中外来资料数据集名称
        private readonly string _foreigndatafiles = "visitors_foreigndatafiles";//mongodb中外来资料相关附件数据集名称

        /// <summary>
        /// 构造方法依赖注入
        /// </summary>
        /// <param name="recordRepository">访问记录仓储</param>
        /// <param name="recordMongoDbRepository">访问记录mongodb仓储</param>
        /// <param name="filesRepository">访客记录相关附件仓储</param>
        /// <param name="filesMongoDbRepository">访客记录相关附件mongodb仓储</param>
        /// <param name="foreignRepository">外来资料仓储</param>
        /// <param name="foreignMongoDbRepository">外来资料mongodb仓储</param>
        /// <param name="foreignFileRepository">外来资料相关附件仓储</param>
        /// <param name="foreignFileMongoDbRepository">外来资料相关附件mongodb仓储</param>
        /// <param name="mechanismService">机构服务</param>
        /// <param name="tkUsersService">用户服务</param>
        /// <param name="dictionaryService">字典服务</param>
        /// <param name="fileService">文件服务</param>
        /// <param name="tkRoleService">角色服务</param>
        public VisitorsRecordService(ISqlSugarRepository<VisitorsRecordEntity> recordRepository,
            IMongoDBRepository<VisitorsRecordEntity> recordMongoDbRepository,
            ISqlSugarRepository<VisitorsFilesEntity> filesRepository,
            IMongoDBRepository<VisitorsFilesEntity> filesMongoDbRepository,
            ISqlSugarRepository<ForeignDataEntity> foreignRepository,
            IMongoDBRepository<ForeignDataEntity> foreignMongoDbRepository,
            ISqlSugarRepository<ForeignDataFilesEntity> foreignFileRepository,
            IMongoDBRepository<ForeignDataFilesEntity> foreignFileMongoDbRepository,
            IMechanismService mechanismService,ITkUsersService tkUsersService, 
            IDictionaryService dictionaryService, IFileService fileService, ITkRoleService tkRoleService)
        {
            _recordRepository = recordRepository;
            _recordMongoDbRepository = recordMongoDbRepository;
            _filesRepository = filesRepository;
            _filesMongoDbRepository = filesMongoDbRepository;
            _foreignRepository = foreignRepository;
            _foreignMongoDbRepository = foreignMongoDbRepository;
            _foreignFileRepository = foreignFileRepository;
            _foreignFileMongoDbRepository = foreignFileMongoDbRepository;
            _mechanismService = mechanismService;
            _tkUsersService = tkUsersService;
            _dictionaryService = dictionaryService;
            _fileService = fileService;
            _tkRoleService = tkRoleService;
            _httpContext = App.HttpContext;
        }

        #region 访客记录
        /// <summary>
        /// 分页获取访客记录数据
        /// </summary>
        /// <param name="query">查询访客记录请求模型</param>
        /// <returns></returns>
        [HttpPost("record/gets")]
        public async Task<TkPageResult<VisitorsRecordListDto>> Gets([FromBody] QueryVisitorsRecordFilterRequestModel query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;

                #region 拼接查询条件
                Expression<Func<VisitorsRecordEntity, bool>> where = r =>
                r.OrganizeId== organizeId && r.DeleteMark == null && 
                (r.CreatorUserId==userId || (r.CreatorUserId != userId && r.EnabledMark==1));
                if (!string.IsNullOrWhiteSpace(query.classifyId))
                {
                    string queryClassifyId = await _dictionaryService.GetIdAsync(query.classifyId, organizeId);
                    where = where.And(m => m.ClassifyId == queryClassifyId);
                }
                if (query.enabledMark == 1) where = where.And(m => m.EnabledMark == 1);
                if (query.enabledMark == 0) where = where.And(m => m.EnabledMark != 1);
                if (query.startTime != null) where = where.And(m => m.CreatorTime >= query.startTime);
                if (query.endTime != null) where = where.And(m => m.CreatorTime <= query.endTime);
                if (!string.IsNullOrWhiteSpace(query.keyword))
                    where = where.And(m => m.Title.Contains(query.keyword));
                #endregion

                var pageList = new SqlSugarPagedList<VisitorsRecordListDto>();
                #region 从mongodb中获取访客记录数据
                //排序生成器
                var builderSort = Builders<VisitorsRecordEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Ascending(r => r.SortCode).Descending(r => r.CreatorTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<VisitorsRecordEntity>, int, int) result =
                    await _recordMongoDbRepository.GetListAsync(_records,
                    where, query.currentPage, query.pageSize, null, sort);
                pageList.list = result.Item1.Adapt<List<VisitorsRecordListDto>>();
                pageList.pagination = new PagedModel()
                {
                    PageIndex = query.currentPage,
                    PageSize = query.pageSize,
                    Total = result.Item2,
                    PageCount = result.Item3
                };
                #endregion

                if (pageList.list == null || pageList.list.Count() <= 0)
                {
                    #region 从sqlserver数据库中获取访客记录数据
                    var sqlResult = await _recordRepository.Entities.Where(where)
                         .OrderBy(r => r.SortCode, OrderByType.Asc)
                         .OrderBy(r => r.CreatorTime, OrderByType.Desc)
                         .ToPagedListAsync(query.currentPage, query.pageSize);
                    pageList.list = sqlResult.list.Adapt<List<VisitorsRecordListDto>>();
                    pageList.pagination = sqlResult.pagination;
                    #endregion
                }

                #region 处理访客记录返回数据
                if (pageList.list.Any())
                {
                    var classifyIds = pageList.list.Select(r => r.classifyId.Split(',').ToList())
                       .SelectMany(r => r).Distinct().ToList();
                    var classifys = await _dictionaryService.GetDictionaryListByIds(classifyIds);
                    var userIds = pageList.list.Select(r => r.creatorUserId).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    pageList.list.ForEach(record => 
                    {
                        if (!string.IsNullOrWhiteSpace(record.classifyId))
                        {
                            record.classifyName = classifys?.FirstOrDefault(r => r.Id == record.classifyId.Split(',').Last())?.Name;
                        }
                        if (!string.IsNullOrWhiteSpace(record.creatorUserId))
                            record.creatorUserName = users?.FirstOrDefault(r => r.Id == record.creatorUserId)?.RealName;
                    });
                }
                #endregion

                return TkPageResult<VisitorsRecordListDto>.Success(pageList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"分页获取访客记录数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取访客记录详细信息
        /// </summary>
        /// <param name="id">访客记录id</param>
        /// <returns></returns>
        [HttpGet("record/get/{id}")]
        public async Task<TkResult<VisitorsRecordDto>> Get([Required] string id)
        {
            try
            {
                var entity = await GetVisitorsRecordInfoAsync(r=>r.Id==id && r.DeleteMark==null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0006);
                var record = entity.Adapt<VisitorsRecordDto>();

                #region 处理访客记录详细返回信息
                if (!string.IsNullOrWhiteSpace(record.classifyId))
                {
                    record.classifyName = string.Join('/', (await _dictionaryService
                   .GetDictionaryListByIds(record.classifyId.Split(',').ToList()))
                   ?.Select(r => r.Name)?.ToList());
                }
                if (!string.IsNullOrWhiteSpace(record.creatorUserId))
                    record.creatorUserName = (await _tkUsersService.GetUserInfoByUserId(record.creatorUserId))?.RealName;
                #endregion

                //获取访客记录相关附件数据
                var fileData = await GetVisitorsFilesListAsync(id);
                record.fileData = fileData.Adapt<List<FileListDto>>();

                return TkResult<VisitorsRecordDto>.Success(record);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取访客记录详细信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加访客记录
        /// </summary>
        /// <param name="input">添加访客记录请求模型</param>
        /// <returns></returns>
        [HttpPost("record/add")]
        public async Task Add([FromBody] AddVisitorsRecordRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                if ((await GetVisitorsRecordInfoAsync(r => r.OrganizeId == organizeId && r.MechanismId== mechanismId &&
                r.ClassifyId == input.classifyId && r.Title == input.title && r.DeleteMark == null)) != null)
                    throw YNTKException.Oh(ErrorCode.Visitors0003);

                var entity = input.Adapt<VisitorsRecordEntity>();
                entity.OrganizeId = organizeId;
                entity.MechanismId = mechanismId;

                //保存访客记录到sqlserver
                var isOk = await _recordRepository.Context.Insertable(entity)
                    .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.Visitors0004);

                //保存访客记录到mongodb
                entity = isOk;
                var result = await _recordMongoDbRepository.AddAsync(entity, _records);
                if (!result) throw YNTKException.Oh(ErrorCode.Visitors0005);

                //保存访客记录相关附件
                await SaveVisitorsFilesAsync(entity.Id,userId, input.fileData);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加访客记录发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 修改访客记录
        /// </summary>
        /// <param name="input">修改访客记录请求模型</param>
        /// <returns></returns>
        [HttpPut("record/update")]
        public async Task Update([FromBody] UpdateVisitorsRecordRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                var entity = await GetVisitorsRecordInfoAsync(r => r.Id == input.id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0006);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);
                if ((await GetVisitorsRecordInfoAsync(r => r.OrganizeId == organizeId && r.MechanismId == mechanismId 
                && r.ClassifyId == input.classifyId && r.Title == input.title && r.Id!=input.id && r.DeleteMark == null)) != null)
                    throw YNTKException.Oh(ErrorCode.Visitors0003);

                entity = input.Mapper(entity);
                //保存访客记录到sqlserver
                entity.OrganizeId = organizeId;
                entity.MechanismId = mechanismId;
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var isOK = await _recordRepository.Context.Updateable(entity)
                .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                if (!(isOK > 0)) throw YNTKException.Oh(ErrorCode.Visitors0007);

                //保存访客记录到mongodb
                var update = await _recordMongoDbRepository.UpdateAsync(entity, _records, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Visitors0008);

                //保存访客记录相关附件
                await SaveVisitorsFilesAsync(entity.Id, userId, input.fileData);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"修改访客记录发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除访客记录
        /// </summary>
        /// <param name="id">访客记录id</param>
        /// <returns></returns>
        [HttpDelete("record/delete/{id}")]
        public async Task Delete([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;

                var entity = await GetVisitorsRecordInfoAsync(r => r.Id ==id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0006);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);

                //从sqlserver中删除
                var isOk = await _recordRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Visitors0009);

                //从mongodb中删除
                var delete = await _recordMongoDbRepository.DeleteAsync(_records, m => m.Id == id);
                if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.Visitors0010);

                //删除访客记录相关附件数据
                await DeleteVisitorsFilesAsync(id);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除访客记录发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 更新访客记录记录状态(启用/禁用)
        /// </summary>
        /// <param name="id">访客记录id</param>
        /// <returns></returns>
        [HttpPut("record/state/{id}")]
        public async Task UpdateState([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;

                var entity = await GetVisitorsRecordInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0006);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);

                var isOk = await _recordRepository.Context.Updateable<VisitorsRecordEntity>()
               .SetColumns(it => new VisitorsRecordEntity()
               {
                   EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                   LastModifyUserId = userId,
                   LastModifyTime = SqlFunc.GetDate()
               }).Where(it => it.Id == id).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Visitors0011);

                entity.EnabledMark = entity.EnabledMark == 1 ? 0 : 1;
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var update = await _recordMongoDbRepository.UpdateAsync(entity, _records, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Visitors0012);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"更新访客记录记录状态(启用/禁用)发生异常：{ex.Message}");
            }
        }


        /// <summary>
        /// 根据条件获取访客记录信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<VisitorsRecordEntity> GetVisitorsRecordInfoAsync(Expression<Func<VisitorsRecordEntity, bool>> where)
        {
            //从从mongodb中获取
            var entity = await _recordMongoDbRepository.GetAsync(_records, where);
            //再从sqlserver中获取
            if (entity == null) entity = await _recordRepository.FirstOrDefaultAsync(where);
            return entity;
        }
        #endregion

        #region 外来资料
        /// <summary>
        /// 分页获取外来资料数据
        /// </summary>
        /// <param name="query">查询外来资料请求模型</param>
        /// <returns></returns>
        [HttpPost("foreigndata/gets")]
        public async Task<TkPageResult<ForeignDataListDto>> GetForeignDataList([FromBody] QueryForeignDataFilterRequestModel query)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;
                string roleId = user.Subject.FindFirst(ClaimConst.ROLEID).Value;
                //账号类型【0.平台运营人员 1.超级管理员 2.组织管理员 3.组织用户 4.第三方登录用户 5.游客用户】
                var authenticationType = user.Subject.FindFirst(ClaimConst.ACCOUNTTYPE).Value;

                #region 拼接查询条件
                Expression<Func<ForeignDataEntity, bool>> where = m =>m.DeleteMark == null;
                if (authenticationType == "2") 
                    where = where.And(m=>m.OrganizeId== organizeId && (
                    (m.CreatorUserId!=userId && m.SharedScope!=4) || m.CreatorUserId==userId));
                else
                {
                    where = where.And(m=>m.CreatorUserId == userId ||
                   (m.SharedScope == 0 && m.OrganizeId == organizeId && m.EnabledMark == 1) ||
                   (m.SharedScope == 1 && m.MechanismId == mechanismId && m.EnabledMark == 1) ||
                   (m.SharedScope == 2 && m.SharedScopeValue.Contains(roleId) && m.EnabledMark == 1) ||
                   (m.SharedScope == 3 && m.SharedScopeValue.Contains(userId) && m.EnabledMark == 1));
                }

                if (query.enabledMark == 1) where = where.And(m => m.EnabledMark == 1);
                if (query.enabledMark == 0) where = where.And(m => m.EnabledMark != 1);
                if (!string.IsNullOrWhiteSpace(query.mechanismId))
                {
                    string queryMechanismId = await _mechanismService.GetIdAsync(query.mechanismId, organizeId);
                    where = where.And(m => m.MechanismId == queryMechanismId);
                }
                if (!string.IsNullOrWhiteSpace(query.classifyId))
                {
                    string queryClassifyId = await _dictionaryService.GetIdAsync(query.classifyId, organizeId);
                    where = where.And(m => m.ClassifyId == queryClassifyId);
                }
                if (query.sharedScope != null)
                    where = where.And(m => m.SharedScope == query.sharedScope.GetHashCode());
                if (query.startTime != null) where = where.And(m => m.CreatorTime >= query.startTime);
                if (query.endTime != null) where = where.And(m => m.CreatorTime <= query.endTime);
                if (!string.IsNullOrWhiteSpace(query.keyword))
                    where = where.And(m => m.Title.Contains(query.keyword));
                #endregion

                var pageList = new SqlSugarPagedList<ForeignDataListDto>();

                #region 先从mongodb中获取外来资料数据
                //排序生成器
                var builderSort = Builders<ForeignDataEntity>.Sort;
                //排序约束   Ascending 正序    Descending 倒序
                var sort = builderSort.Ascending(r => r.SortCode).Descending(r => r.CreatorTime);
                //Item1.结果集 Item2.总条数 Item3.总页数
                (List<ForeignDataEntity>, int, int) result =
                    await _foreignMongoDbRepository.GetListAsync(_foreigndata,
                    where, query.currentPage, query.pageSize, null, sort);
                pageList.list = result.Item1.Adapt<List<ForeignDataListDto>>();
                pageList.pagination = new PagedModel()
                {
                    PageIndex = query.currentPage,
                    PageSize = query.pageSize,
                    Total = result.Item2,
                    PageCount = result.Item3
                };
                #endregion

                if (!pageList.list.Any())
                {
                    #region 再从sqlserver中获取工作记录数据
                    var sqlResult = await _foreignRepository.Entities.Where(where)
                        .OrderBy(r => r.SortCode, OrderByType.Asc)
                        .OrderBy(r => r.CreatorTime, OrderByType.Desc)
                        .ToPagedListAsync(query.currentPage, query.pageSize);
                    pageList.list = sqlResult.list.Adapt<List<ForeignDataListDto>>();
                    pageList.pagination = sqlResult.pagination;
                    #endregion
                }

                #region 处理外来资料返回数据
                if (pageList.list.Any())
                {
                    var mechanismIds = pageList.list.Where(r => !string.IsNullOrWhiteSpace(r.mechanismId))
                        ?.Select(r => r.mechanismId.Split(',').ToList())
                        ?.SelectMany(r => r).Distinct().ToList();
                    var mechanisms = !mechanismIds.Any() ? new List<MechanismEntity>() :
                        await _mechanismService.GetMechanismListAsync(null, mechanismIds);
                    var classifyIds = pageList.list.Select(r => r.classifyId.Split(',').ToList())
                       .SelectMany(r => r).Distinct().ToList();
                    var classifys = await _dictionaryService.GetDictionaryListByIds(classifyIds);
                    var userIds = pageList.list.Select(r => r.creatorUserId).Distinct().ToList();
                    var users = await _tkUsersService.GetUserListByIds(userIds);
                    pageList.list.ForEach(item =>
                    {
                        item.sharedScopeText = EnumHelper.GetEnumDescriptionString
                        (item.sharedScope, typeof(SharedScopeEnum));
                        if (!string.IsNullOrWhiteSpace(item.mechanismId))
                        {
                            item.mechanismName = mechanisms?.FirstOrDefault(r => r.Id == item.mechanismId.Split(',').Last())?.Name;
                        }
                        if (!string.IsNullOrWhiteSpace(item.classifyId))
                        {
                            item.classifyName = classifys?.FirstOrDefault(r => r.Id == item.classifyId.Split(',').Last())?.Name;
                        }
                        item.creatorUserName = users?.FirstOrDefault(r => r.Id == item.creatorUserId)?.RealName;
                    });
                }
                #endregion

                return TkPageResult<ForeignDataListDto>.Success(pageList);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"分页获取外来资料数据发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 获取外来资料详细信息
        /// </summary>
        /// <param name="id">外来资料id</param>
        /// <returns></returns>
        [HttpGet("foreigndata/get/{id}")]
        public async Task<TkResult<ForeignDataInfoDto>> GetForeignDataInfo([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                var entity = await GetForeignDataInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0015);

                var result = entity.Adapt<ForeignDataInfoDto>();

                #region 处理外来资料返回信息
                result.sharedScopeText = EnumHelper.GetEnumDescriptionString
                        (result.sharedScope, typeof(SharedScopeEnum));
                if (!string.IsNullOrWhiteSpace(result.mechanismId) && result.mechanismId != "jg000000")
                {
                    result.mechanismName = string.Join('/', (await _mechanismService
                        .GetMechanismListAsync(null, result.mechanismId.Split(',').ToList()))
                        ?.Select(r => r.Name)?.ToList());
                }
                if (!string.IsNullOrWhiteSpace(result.classifyId))
                {
                    result.classifyName = string.Join('/', (await _dictionaryService
                   .GetDictionaryListByIds(result.classifyId.Split(',').ToList()))
                   ?.Select(r => r.Name)?.ToList());
                }
                #region 处理共享范围
                if (!string.IsNullOrWhiteSpace(result.sharedScopeValue))
                {
                    //共享范围(0.全组织 1.特定机构 2.特定角色 3.特定用户 4.仅自己可见)
                    switch (result.sharedScope)
                    {
                        case 0:
                            result.sharedScopeValueText = "全组织";
                            break;
                        case 1:
                            var dic = await _mechanismService.GetIdsAsync(result.sharedScopeValue.Split(',').ToList(), organizeId);
                            var values = dic.Values.ToList();
                            result.sharedScopeValueText = string.Join(',', values.Select(r => r.Item2).ToList());
                            result.sharedScopeMechanismValue = values.Select(r => r.Item1.Split(',').ToArray())?.ToList();
                            break;
                        case 2:
                            result.sharedScopeValueText = string.Join(',', (await _tkRoleService
                                .GetTkRoleListByIdsAsync(result.sharedScopeValue.Split(',').ToList()))
                                ?.Select(r => r.Name)?.ToList());
                            break;
                        case 3:
                            result.sharedScopeValueText = string.Join(',', (await _tkUsersService
                               .GetUserListByIds(result.sharedScopeValue.Split(',').ToList()))
                               ?.Select(r => r.RealName)?.ToList());
                            break;
                        case 4:
                            result.sharedScopeValueText = "仅自己可见";
                            break;
                    }
                }
                #endregion
                if (!string.IsNullOrWhiteSpace(result.creatorUserId))
                    result.creatorUserName = (await _tkUsersService.GetUserInfoByUserId(result.creatorUserId))?.RealName;
                #endregion

                //获取外来资料相关附件数据
                var fileData = await GetForeignDataFilesListAsync(id);
                result.fileData = fileData.Adapt<List<CommonFileListDto>>();

                #region 累加浏览次数
                entity.ViewCount++;
                await _foreignRepository.Context.Updateable(entity)
                    .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                await _foreignMongoDbRepository.UpdateAsync(entity, _foreigndata, m => m.Id == entity.Id);
                #endregion

                return TkResult<ForeignDataInfoDto>.Success(result);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"获取外来资料详细信息发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 添加外来资料
        /// </summary>
        /// <param name="input">添加外来资料请求模型</param>
        /// <returns></returns>
        [HttpPost("foreigndata/add")]
        public async Task AddForeignData([FromBody] AddForeignDataRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                if ((await GetForeignDataInfoAsync(r => r.OrganizeId == organizeId && r.ClassifyId == input.classifyId &&
                r.MechanismId == mechanismId && r.Title == input.title && r.DeleteMark == null)) != null)
                    throw YNTKException.Oh(ErrorCode.Visitors0016);

                var entity = input.Adapt<ForeignDataEntity>();
                entity.SharedScope = input.sharedScope.GetHashCode();
                entity.OrganizeId = organizeId;
                entity.MechanismId = mechanismId;

                //保存外来资料到sqlserver
                var isOk = await _foreignRepository.Context.Insertable(entity)
                   .CallEntityMethod(m => m.Creator()).ExecuteReturnEntityAsync();
                _ = isOk ?? throw YNTKException.Oh(ErrorCode.Visitors0017);

                //保存外来资料到mongodb
                entity = isOk;
                var result = await _foreignMongoDbRepository.AddAsync(entity, _foreigndata);
                if (!result) throw YNTKException.Oh(ErrorCode.Visitors0018);

                //保存外来资料相关附件
                await SaveForeignDataFilesAsync(entity.Id,userId, input.fileData);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"添加外来资料发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 修改外来资料
        /// </summary>
        /// <param name="input">修改外来资料请求模型</param>
        /// <returns></returns>
        [HttpPut("foreigndata/update")]
        public async Task UpdateForeignData([FromBody] UpdateForeignDataRequestModel input)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;
                string organizeId = user.Subject.FindFirst(ClaimConst.ORGANIZEID).Value;
                string mechanismId = user.Subject.FindFirst(ClaimConst.MECHANISMID).Value;

                var entity = await GetForeignDataInfoAsync(r => r.Id == input.id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0015);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);
                if ((await GetForeignDataInfoAsync(r => r.OrganizeId == organizeId && r.ClassifyId == input.classifyId &&
                r.MechanismId == mechanismId && r.Title == input.title && r.Id != input.id && r.DeleteMark == null)) != null) 
                    throw YNTKException.Oh(ErrorCode.Visitors0016);

                entity = input.Mapper(entity);
                entity.SharedScope = input.sharedScope.GetHashCode();
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;

                //保存外来资料到sqlserver
                var isOK = await _foreignRepository.Context.Updateable(entity)
               .IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
                if (!(isOK > 0)) throw YNTKException.Oh(ErrorCode.Visitors0019);

                //保存外来资料到mongodb
                var update = await _foreignMongoDbRepository.UpdateAsync(entity, _foreigndata, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Visitors0020);

                //保存外来资料相关附件
                await SaveForeignDataFilesAsync(entity.Id,userId, input.fileData);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"修改外来资料发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除外来资料
        /// </summary>
        /// <param name="id">外来资料id</param>
        /// <returns></returns>
        [HttpDelete("foreigndata/delete/{id}")]
        public async Task DeleteForeignData([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;

                var entity = await GetForeignDataInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0015);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);

                //从sqlserver中删除
                var isOk = await _foreignRepository.Context.Deleteable(entity).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Visitors0021);

                //从mongodb中删除
                var delete = await _foreignMongoDbRepository.DeleteAsync(_foreigndata, m => m.Id == id);
                if (!(delete > 0)) throw YNTKException.Oh(ErrorCode.Visitors0022);

                //删除外来资料相关附件
                await DeleteForeignDataFilesAsync(id);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"删除外来资料发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 更新外来资料状态(启用/禁用)
        /// </summary>
        /// <param name="id">外来资料id</param>
        /// <returns></returns>
        [HttpPut("foreigndata/state/{id}")]
        public async Task UpdateForeignDataState([Required] string id)
        {
            try
            {
                var user = _httpContext.User.FindFirst(ClaimConst.CLAINM_USERID);
                string userId = user.Value;

                var entity = await GetForeignDataInfoAsync(r => r.Id == id && r.DeleteMark == null);
                _ = entity ?? throw YNTKException.Oh(ErrorCode.Visitors0015);
                if (entity.CreatorUserId != userId) throw YNTKException.Oh(ErrorCode.D1016);

                //sqlserver更新外来资料状态
                var isOk = await _foreignRepository.Context.Updateable<ForeignDataEntity>()
               .SetColumns(it => new ForeignDataEntity()
               {
                   EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
                   LastModifyUserId = userId,
                   LastModifyTime = SqlFunc.GetDate()
               }).Where(it => it.Id == id).ExecuteCommandAsync();
                if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Visitors0023);

                //mongodb更新外来资料状态
                entity.EnabledMark = entity.EnabledMark == 1 ? 0 : 1;
                entity.LastModifyTime = DateTime.Now;
                entity.LastModifyUserId = userId;
                var update = await _foreignMongoDbRepository.UpdateAsync(entity, _foreigndata, m => m.Id == entity.Id);
                if (!(update.ModifiedCount > 0)) throw YNTKException.Oh(ErrorCode.Visitors0024);
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"更新外来资料状态(启用/禁用)发生异常：{ex.Message}");
            }
        }



        /// <summary>
        /// 根据条件获取外来资料信息
        /// </summary>
        /// <param name="where">条件</param>
        /// <returns></returns>
        private async Task<ForeignDataEntity> GetForeignDataInfoAsync(Expression<Func<ForeignDataEntity, bool>> where)
        {
            //从从mongodb中获取
            var entity = await _foreignMongoDbRepository.GetAsync(_foreigndata, where);
            //再从sqlserver中获取
            if (entity == null) entity = await _foreignRepository.FirstOrDefaultAsync(where);
            return entity;
        }
        #endregion

        #region 访客记录相关附件
        /// <summary>
        /// 获取访客记录相关附件数据
        /// </summary>
        /// <param name="recordId">访客记录id</param>
        /// <returns></returns>
        private async Task<List<VisitorsFilesEntity>> GetVisitorsFilesListAsync(string recordId)
        {
            //从mongodb中获取附件数据
            var result = await _filesMongoDbRepository.GetListAsync(_files, r => r.RecordId == recordId);
            if (!result.Any())
            {
                //从sqlserver数据库中获取附件数据
                result = await _filesRepository.Entities.Where(r => r.RecordId == recordId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存访客记录相关附件
        /// </summary>
        /// <param name="recordId">访客记录id</param>
        /// <param name="userId">当前用户id</param>
        /// <param name="fileData">相关附件数据</param>
        /// <returns></returns>
        private async Task SaveVisitorsFilesAsync(string recordId,string userId, List<FileRequestModel> fileData)
        {
            try
            {
                _filesRepository.Ado.BeginTran();
                //删除原数据
                await _filesMongoDbRepository.DeleteAsync(_files, r => r.RecordId == recordId);
                await _filesRepository.DeleteAsync(r => r.RecordId == recordId);
                if (fileData != null && fileData.Count > 0)
                {
                    var files = new List<VisitorsFilesEntity>();
                    var file = new VisitorsFilesEntity();
                    fileData.ForEach(item =>
                    {
                        file = item.Adapt<VisitorsFilesEntity>();
                        file.Id = YitIdHelper.NextId().ToString();
                        file.RecordId = recordId;
                        file.CreatorUserId = userId;
                        file.CreatorTime =DateTime.Now;
                        files.Add(file);
                    });
                    //保存到sqlserver                 
                    var isOk = await _filesRepository.Context.Insertable(files).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Visitors0001);
                    //保存到mongodb
                    var succeed = await _filesMongoDbRepository.AddListAsync(files, _files);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.Visitors0002);
                }
                _filesRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _filesRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存访客记录相关附件发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除访客记录相关附件数据
        /// </summary>
        /// <param name="recordId">访客记录id</param>
        /// <returns></returns>
        private async Task DeleteVisitorsFilesAsync(string recordId)
        {
            var result = await GetVisitorsFilesListAsync(recordId);
            if (result.Any())
            {
                //删除原数据
                await _filesMongoDbRepository.DeleteAsync(_files, r => r.RecordId == recordId);
                await _filesRepository.DeleteAsync(r => r.RecordId == recordId);
                //删除文件
                var deleteFiles = result.Adapt<List<FileListDto>>();
                _fileService.DeleteFiles(deleteFiles);
            }
        }
        #endregion

        #region 外来资料相关附件
        /// <summary>
        /// 获取外来资料相关附件数据
        /// </summary>
        /// <param name="foreignDataId">外来资料id</param>
        /// <returns></returns>
        private async Task<List<ForeignDataFilesEntity>> GetForeignDataFilesListAsync(string foreignDataId)
        {
            //从mongodb中获取附件数据
            var result = await _foreignFileMongoDbRepository.GetListAsync(_foreigndatafiles, r => r.ForeignDataId == foreignDataId);
            if (!result.Any())
            {
                //从sqlserver数据库中获取附件数据
                result = await _foreignFileRepository.Entities.Where(r => r.ForeignDataId == foreignDataId).ToListAsync();
            }
            return result;
        }

        /// <summary>
        /// 保存外来资料相关附件
        /// </summary>
        /// <param name="foreignDataId">外来资料id</param>
        /// <param name="userId">当前用户id</param>
        /// <param name="fileData">相关附件数据</param>
        /// <returns></returns>
        private async Task SaveForeignDataFilesAsync(string foreignDataId, string userId, List<CommonFileRequestModel> fileData)
        {
            try
            {
                _foreignFileRepository.Ado.BeginTran();
                //删除原数据
                await _foreignFileMongoDbRepository.DeleteAsync(_foreigndatafiles, r => r.ForeignDataId == foreignDataId);
                await _foreignFileRepository.DeleteAsync(r => r.ForeignDataId == foreignDataId);
                if (fileData != null && fileData.Count > 0)
                {
                    var files = new List<ForeignDataFilesEntity>();
                    var file = new ForeignDataFilesEntity();
                    fileData.ForEach(item =>
                    {
                        file = item.Adapt<ForeignDataFilesEntity>();
                        file.Id = YitIdHelper.NextId().ToString();
                        file.ForeignDataId = foreignDataId;
                        file.CreatorUserId = userId;
                        file.CreatorTime = DateTime.Now;
                        files.Add(file);
                    });
                    //保存到sqlserver                 
                    var isOk = await _foreignFileRepository.Context.Insertable(files).ExecuteCommandAsync();
                    if (!(isOk > 0)) throw YNTKException.Oh(ErrorCode.Visitors0013);
                    //保存到mongodb
                    var succeed = await _foreignFileMongoDbRepository.AddListAsync(files, _foreigndatafiles);
                    if (!succeed) throw YNTKException.Oh(ErrorCode.Visitors0014);
                }
                _foreignFileRepository.Ado.CommitTran();
            }
            catch (Exception ex)
            {
                _foreignFileRepository.Ado.RollbackTran();
                if (ex.Message.Contains("[")) throw YNTKException.Oh($"{ex.Message}");
                throw YNTKException.Oh($"保存外来资料相关附件发生异常：{ex.Message}");
            }
        }

        /// <summary>
        /// 删除外来资料相关附件数据
        /// </summary>
        /// <param name="foreignDataId">外来资料id</param>
        /// <returns></returns>
        private async Task DeleteForeignDataFilesAsync(string foreignDataId)
        {
            var result = await GetForeignDataFilesListAsync(foreignDataId);
            if (result.Any())
            {
                //删除原数据
                await _foreignFileMongoDbRepository.DeleteAsync(_foreigndatafiles, r => r.ForeignDataId == foreignDataId);
                await _foreignFileRepository.DeleteAsync(r => r.ForeignDataId == foreignDataId);
                //删除文件
                var deleteFiles = result.Adapt<List<FileListDto>>();
                _fileService.DeleteFiles(deleteFiles);
            }
        }
        #endregion

    }
}
